import random
import subprocess
import time
import hmac
import hashlib
import base64
import urllib.parse
from multiprocessing import Queue, Process

import requests
import json

laibo_account = None
change_accounts = []
zones = []

googleAccount = "postkandisyg21@gmail.com"
project_pre = googleAccount.split("@gmail.com")[0]
project_range = range(1, 4)  # 不包含右边
do_create_project = True

error_info = []
error_info.append("Permission denied on 'locations")
error_info.append("does not have enough resources available to fulfill the request")
error_info.append("does not exist in zone")


def create_project(project, do_create_project):
    if not do_create_project:
        return project
        # 创建项目
    while True:
        cmd_create = "gcloud projects create {}".format(project)
        (status, create_res) = subprocess.getstatusoutput(cmd_create)
        if "The project ID you specified is already in use by another project" in create_res:
            name, number = project.split("-", -1)
            project = name + "-" + str(int(number) + 1)
            print("create same name project , change name to {}".format(project))
        elif "The project cannot be created because you have exceeded your allotted project quota" in create_res:
            print("project number limit ,done process")
            exit(0)
        else:
            # todo 判断成功的条件
            print(create_res)
            return project


def set_project(project):
    #  指定项目
    cmd_set_project = "gcloud config set project " + project
    (status, set_project_res) = subprocess.getstatusoutput(cmd_set_project)
    if "ERROR" in set_project_res:
        print(set_project_res)
        exit(0)
    else:
        print("set project success")


def get_billing_account():
    global laibo_account
    global change_accounts
    # 获取结算账号
    cmd_billing_list = "gcloud beta billing accounts list --filter=open=true"
    (status, cmd_billing_list_res) = subprocess.getstatusoutput(cmd_billing_list)
    billing_account = cmd_billing_list_res.strip().split("\n")[1:]

    for line in billing_account:
        if "baidao" in line:
            temp = [s for s in line.split(" ") if not s == ""]
            laibo_account = temp[:2][0]
        elif "gmail.com" in line:
            temp = [s for s in line.split(" ") if not s == ""]
            temp_account = temp[:2]
            change_accounts.append(temp_account)


def set_baidao_billing(project):
    # 指定结算账号到baidao
    cmd_link_baido_billing = "gcloud beta billing projects link " + project + "  --billing-account " + laibo_account
    (status, billing_link_baidao_res) = subprocess.getstatusoutput(cmd_link_baido_billing)
    print(billing_link_baidao_res)
    if "ERROR" in billing_link_baidao_res:
        exit(0)
    else:
        print("success change account billing to baido")


def enable_api():
    # 开启api
    cmd_enable_api = "gcloud services enable compute.googleapis.com"
    (status, enable_api_res) = subprocess.getstatusoutput(cmd_enable_api)
    print(enable_api_res)
    if "ERROR" in enable_api_res:
        print(" enable compute engine Manual")
        exit(0)


def get_server_account():
    # 获取 server account
    cmd_get_account = "gcloud iam service-accounts list"
    (status, service_account_res) = subprocess.getstatusoutput(cmd_get_account)
    if "ERROR" in service_account_res:
        print(service_account_res)
        exit(0)
    service_account = \
        [s for s in
         [line for line in service_account_res.strip().split("/n") if "default service account" in line][0].split(" ")
         if
         "compute@developer.gserviceaccount.com" in s][0]
    print("success get default account: {}".format(service_account))

    return service_account


def get_zones():
    # zones = "europe-north1-a,europe-north1-b,europe-north1-c," \
    #         "europe-west1-b,europe-west1-c,europe-west1-d," \
    #         "europe-west2-a,europe-west2-b,europe-west2-c," \
    #         "europe-west3-a,europe-west3-b,europe-west3-c," \
    #         "europe-west4-a,europe-west4-b,europe-west4-c," \
    #         "europe-west6-a,europe-west6-b,europe-west6-c," \
    #         "northamerica-northeast1-a,northamerica-northeast1-b,northamerica-northeast1-c," \
    #         "southamerica-east1-a,southamerica-east1-b,southamerica-east1-c," \
    #         "us-central1-a,us-central1-b,us-central1-c,us-central1-f," \
    #         "us-east1-b,us-east1-c,us-east1-d," \
    #         "us-east4-a,us-east4-b,us-east4-c," \
    #         "us-west1-a,us-west1-b,us-west1-c," \
    #         "us-west4-a,us-west4-b,us-west4-c".split(",")

    areas = ["us-central1-", "us-east1-", "us-east4-", "us-west1-", "us-west4-",
             "southamerica-east1-", "northamerica-northeast1-", "europe-north1-", "europe-west1-",
             "europe-west2-", "europe-west3-", "europe-west4-", "europe-west6-"]
    labels = ['a', 'b', 'c', 'd', 'f']

    for area in areas:
        for label in labels:
            zones.append(area + label)
    return zones


def run(project, service_account, p_index, share_list, share_dict, lock):
    # 开始创建实例
    total = 0
    zone = None
    while len(share_list) > 0:
        do_index = p_index % len(share_list)
        zone = share_list[do_index]
        lock.acquire()
        i = share_dict.get(zone, 0) + 1
        share_dict[zone] = i
        lock.release()
        cmd = "gcloud beta compute --project=" + project + " instances create " + project + "-mm-" + str(
            i) + " --zone=" + zone + " --machine-type=c2-standard-16 --subnet=default --network-tier=PREMIUM --maintenance-policy=MIGRATE --service-account=" + service_account + " --scopes=https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring.write,https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/service.management.readonly,https://www.googleapis.com/auth/trace.append --image=image-2 --image-project=chia01-313911 --boot-disk-size=20GB --boot-disk-type=pd-balanced --boot-disk-device-name=chia06-defoegeraldine-mm-" + str(
            i) + " --create-disk=mode=rw,size=900,type=projects/essaycheck/zones/us-central1-a/diskTypes/pd-balanced,name=disk-mm-" + str(
            i) + ",device-name=disk-mm-" + str(
            i) + " --local-ssd=interface=NVME --local-ssd=interface=NVME --local-ssd=interface=NVME --local-ssd=interface=NVME --local-ssd=interface=NVME --local-ssd=interface=NVME --local-ssd=interface=NVME --local-ssd=interface=NVME --no-shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring --reservation-affinity=any;sleep 1;"
        (status, uploadRes) = subprocess.getstatusoutput(cmd)
        if "ERROR" in uploadRes or "does not have enough resources" in uploadRes:
            if not (error_info[0] in uploadRes or error_info[1] in uploadRes or uploadRes[2] in uploadRes):
                print(uploadRes)
            if "already exists" in uploadRes:
                continue
            else:
                share_list.pop(do_index)
            break
        total += 1
    print("{}  成功: {} 个".format(zone, total))


def list_instance(project):
    # 列出已生成实例
    cmd_list_instances = "gcloud beta compute --project=" + project + " instances list|awk '{print$5}'"
    print("success instance:")
    (status, list_res) = subprocess.getstatusoutput(cmd_list_instances)
    ips = list_res.strip().split("\n")[1:]
    print("success number: {}".format(len(ips)))
    print(list_res)
    info = build_dingding_info(project, ips)
    dingding(info)


def set_not_baidao_billing(project):
    # 绑定结算账号
    for account in change_accounts:
        cmd_link_billing = "gcloud beta billing projects link " + project + "  --billing-account " + account[0]
        (status, billing_link_res) = subprocess.getstatusoutput(cmd_link_billing)
        if "ERROR" in billing_link_res:
            continue
        else:
            print("change billing success —————— " + billing_link_res)
    print("\nerror: change billing account Manual!!!\n")


def get_all_result(googleAccount):
    cmd_list_projects = "gcloud projects list"
    (status, list_project_res) = subprocess.getstatusoutput(cmd_list_projects)
    projects = list_project_res.strip().split("\n")[1:]
    projects = [[item for item in line.split(" ") if not item == ""] for line in projects]
    projects = [{"id": item[0], "name": item[1], "number": item[2]} for item in projects]
    result = {"googleAccount": googleAccount}
    result["project_number"] = len(projects)
    project_lsit = []
    for project in projects:
        tmp = dict()
        tmp["project"] = project
        project_id = project.get("id")
        cmd_list_instance = "gcloud beta compute --project=" + project_id + " instances list|awk '{print$5}'"
        (status, list_instance_res) = subprocess.getstatusoutput(cmd_list_instance)
        instances = list_instance_res.strip().split("\n")[1:]
        tmp["instances"] = instances
        tmp["instance_number"] = len(instances)
        project_lsit.append(tmp)
    result["projects"] = project_lsit
    return json.dumps(result)


def find_instance(ips):
    cmd_list_projects = "gcloud projects list"
    (status, list_project_res) = subprocess.getstatusoutput(cmd_list_projects)
    projects = list_project_res.strip().split("\n")[1:]
    projects = [[item for item in line.split(" ") if not item == ""] for line in projects]
    projects = [{"id": item[0], "name": item[1], "number": item[2]} for item in projects]
    for project in projects:
        project_id = project.get("id")
        cmd_list_instance = "gcloud beta compute --project=" + project_id + " instances list|awk '{print$5}'"
        (status, list_instance_res) = subprocess.getstatusoutput(cmd_list_instance)
        for ip in ips:
            if ip in list_instance_res:
                print()


def read(q):
    zones = ["us-central1-", "us-east1-", "us-east4-", "us-west1-", "us-west4-",
             "southamerica-east1-", "northamerica-northeast1-", "europe-north1-", "europe-west1-",
             "europe-west2-", "europe-west3-", "europe-west4-", "europe-west6-"]
    for k in ['a', 'b', 'c', 'd', 'f']:
        for z in zones:
            zones_end = z + k
            q.put(zones_end)
    for _ in range(1, 50):
        q.put("-1")


count = 1


def deal(j, q, service_account):
    global count
    while 1:
        zones_end = q.get()
        if zones_end == '-1':
            break
        for i in range(1, 15):
            cmd = "gcloud beta compute --project=" + project + " instances create " + project + "-mm-" + str(
                random.randint(1,
                               10000)) + " --zone=" + zones_end + " --machine-type=c2-standard-16 --subnet=default --network-tier=PREMIUM --maintenance-policy=MIGRATE --service-account=" + service_account + " --scopes=https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring.write,https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/service.management.readonly,https://www.googleapis.com/auth/trace.append --image=image-2 --image-project=chia01-313911 --boot-disk-size=20GB --boot-disk-type=pd-balanced --boot-disk-device-name=chia06-defoegeraldine-mm-" + str(
                random.randint(1,
                               10000)) + " --create-disk=mode=rw,size=900,type=projects/essaycheck/zones/us-central1-a/diskTypes/pd-balanced,name=disk-mm-" + str(
                random.randint(1, 10000)) + ",device-name=disk-mm-" + str(random.randint(1,
                                                                                         10000)) + " --local-ssd=interface=NVME --local-ssd=interface=NVME --local-ssd=interface=NVME --local-ssd=interface=NVME --local-ssd=interface=NVME --local-ssd=interface=NVME --local-ssd=interface=NVME --local-ssd=interface=NVME --no-shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring --reservation-affinity=any;sleep 1;"
            (status, uploadRes) = subprocess.getstatusoutput(cmd)
            if "ERROR" in uploadRes or "does not have enough resources" in uploadRes:
                if not (error_info[0] in uploadRes or error_info[1] in uploadRes or uploadRes[2] in uploadRes):
                    print(uploadRes)
                if "already exists" in uploadRes:
                    continue
                break
            else:
                print(str(count) + "个搞好了")
                count = count + 1


def dingding(info):
    '''
    对接钉钉消息通知
    '''
    # 获取时间
    timestamp = str(round(time.time() * 1000))
    secret = 'this is secret'
    secret_enc = secret.encode('utf-8')
    string_to_sign = '{}\n{}'.format(timestamp, secret)
    string_to_sign_enc = string_to_sign.encode('utf-8')
    hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
    sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))

    access_token = 'ff7730d3cc392ec37da8cdab41a491165202e159c3a6770f8213f84d9891b83c'
    url = 'https://oapi.dingtalk.com/robot/send?access_token={}&timestamp={}&sign={}'.format(access_token,
                                                                                             timestamp, sign)
    # 获取当前时间
    str_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
    # 发送的消息格式
    data = {"msgtype": "markdown",
            "markdown": {
                "title": "测试已完成",
                "text": info
            },
            "at": {"atMobiles": ["18062102798"]}
            }
    headers = {'Content-Type': 'application/json'}
    message = requests.post(url, json.dumps(data), headers=headers).json()
    # 将操作的状态记录到日志中
    if message['errmsg'] == 'ok':
        return print('钉钉消息推送成功')
    else:
        return print('钉钉消息推送失败')


def build_dingding_info(project, ips):
    ips_format = ""
    i = 1
    for ip in ips:
        ips_format += "{}. {} \n ".format(i, ip)
    info = "## 测试：谷歌创建实例 \n \n #### {} 创建个数： {}  \n {}".format(project, len(ips), ips_format)
    return info


if __name__ == '__main__':
    print("开始: {}".format(time.strftime("%Y-%m-%d %H-%M-%S", time.localtime())))
    for index in project_range:
        project = project_pre + "-" + str(index)
        project = create_project(project, do_create_project)
        set_project(project)
        get_billing_account()
        set_baidao_billing(project)
        enable_api()
        service_account = get_server_account()

        p_list = []
        p_count = 20
        # get_zones()
        # share_list = mp.Manager().list()
        # share_dict = mp.Manager().dict()
        # lock = mp.Manager().Lock()
        # for i in range(p_count):
        #     p = mp.Process(target=run, args=(project, service_account, i, share_list, share_dict, lock))
        #     p.start()
        #     p_list.append(p)
        # for p in p_list:
        #     p.join()

        q = Queue(maxsize=1000)
        p1 = Process(target=read, args=(q,))
        p1.daemon = True
        p1.start()
        for i in range(p_count):
            p = Process(target=deal, args=(i, q, service_account))
            p.start()
            p_list.append(p)
        for p in p_list:
            p.join()

        set_not_baidao_billing(project)
        list_instance(project)
    print("结束: {}".format(time.strftime("%Y-%m-%d %H-%M-%S", time.localtime())))
